package com.zysoft.common.dao.hibernate4Impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.Id;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import com.zysoft.common.dao.ICommonDao;
import com.zysoft.common.entity.AbstractEntity;

@Repository("CommonDao")
public class CommonHibernate4DaoImpl implements ICommonDao {

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;
    
    public Session getSession() {
        return sessionFactory.getCurrentSession();
    } 
    
	@Override
	public <T extends AbstractEntity> T save(T model) {
		// TODO Auto-generated method stub
		return (T) getSession().save(model);
	}

	@Override
	public <T extends AbstractEntity> void saveOrUpdate(T model) {
		// TODO Auto-generated method stub
		getSession().saveOrUpdate(model);
	}

	@Override
	public <T extends AbstractEntity> void update(T model) {
		// TODO Auto-generated method stub
		getSession().update(model);
	}

	@Override
	public <T extends AbstractEntity> void merge(T model) {
		// TODO Auto-generated method stub
		getSession().merge(model);
	}

	@Override
	public <T extends AbstractEntity, PK extends Serializable> void delete(
			Class<T> entityClass, PK id) {
		// TODO Auto-generated method stub
		getSession().delete(get(entityClass, id));
	}

	@Override
	public <T extends AbstractEntity> void deleteObject(T model) {
		// TODO Auto-generated method stub
		getSession().delete(model);
	}

	@Override
	public <T extends AbstractEntity, PK extends Serializable> T get(
			Class<T> entityClass, PK id) {
		// TODO Auto-generated method stub
		return (T) getSession().get(entityClass, id);
	}

	@Override
	public int executeUpdate(String hqlUpdate, Object... paramlist) {
		// TODO Auto-generated method stub
        Query query = getSession().createQuery(hqlUpdate);
        if(paramlist!=null && paramlist.length==1 && (paramlist[0] instanceof Map<?,?>))
        	setParameters(query, (Map<String, Object>)paramlist[0]);
        else
        	setParameters(query, paramlist);
        return query.executeUpdate();
	}
	
    protected void setParameters(Query query, final Map<String, Object> map){
    	if(map != null){
    		for (Entry<String, Object> e : map.entrySet()) {
    			Object value = e.getValue();
    			if(value instanceof Long)
    				query.setLong(e.getKey(), (Long) value);	
    			else if(value instanceof Integer)
    				query.setInteger(e.getKey(), (Integer) value);
    			else if(value instanceof Boolean)
    				query.setBoolean(e.getKey(), (Boolean) value);
    			else if(value instanceof Date)
    				query.setTimestamp(e.getKey(), (Date) value);
    			else if(value instanceof Collection<?>)
    				query.setParameterList(e.getKey(), (Collection<?>) value);
    			else
    				query.setString(e.getKey(), value.toString());
            }
    	}
    }
    
    protected void setParameters(Query query, Object[] paramlist) {
        if (paramlist != null) {
            for (int i = 0; i < paramlist.length; i++) {
                if(paramlist[i] instanceof Date) {
                    //TODO 难道这是bug 使用setParameter不行？？
                    query.setTimestamp(i, (Date)paramlist[i]);
                }else {
                    query.setParameter(i, paramlist[i]);
                }
            }
        }
    }
    
    protected Field getPrimaryKey(Class entityClass){
    	Field[] fields = entityClass.getDeclaredFields();
    	Field primaryKey = null;
        for(Field f : fields) {
            if(f.isAnnotationPresent(Id.class)) {
            	primaryKey = f;
            }
        }
        return primaryKey;
    }
    
}
